| Miles Sound System SDK 7.2a |
Any model other than peer-to-peer will require that data be buffered and mixed on one or more servers, in preparation for transmission to clients. Fortunately, given the tight constraints on PCM data formats used for voice communication, it's difficult to imagine an easier audio programming job. Mixing of 16-bit signed PCM data is accomplished by means of simple algebraic addition of the corresponding samples from each client buffer, followed by a hard clamping operation to avoid distortion due to sample data overflow. The lack of any need for sample rate conversion, volume scaling, or reformatting enables a simple C/C++ loop to do the job efficiently.
It's important to mix the data from each client at higher-than-16-bit precision, performing the clipping operation only after all samples have been added. Doing so actually reduces the amount of sample points that ultimately have to be clipped, since each incoming waveform sample point has a roughly equal chance of causing an overflow condition or canceling an existing one. MSSCHTS.CPP illustrates how 16-bit sample data may be mixed at 32-bit precision:
// ------------------------------------------------------------
// Merge data from all active clients into each client's
// mixer buffer
// ------------------------------------------------------------
for (i=0; i < N_CLIENTS; i++)
{
CLIENT *C = &clients[i];
//
// If not actively streaming, skip further foreground processing
//
if (!C->in_use)
{
continue;
}
//
// Clear client's mixer buffer to signed-PCM 0 value (0x0000)
//
memset(C->mixer_buffer,
0,
sizeof(C->mixer_buffer));
//
// Add samples from each contributing client's decode buffer to
// target's mixing buffer
//
for (S32 j=0; j < N_CLIENTS; j++)
{
CLIENT *SRC = &clients[j];
//
// Avoid echoing each client's own traffic back to it, unless
// we've enabled local echo as a diagnostic option
//
if (SendMessage(hear,BM_GETCHECK,0,0)==0)
{
if (i == j)
{
continue;
}
}
//
// Skip inactive or newly-logged-on clients that don't have
// enough data buffered yet
//
if (SRC->samples_to_mix == 0)
{
continue;
}
//
// Add 16-bit data to 32-bit output buffer
//
S16 *src = SRC->fetch_buffer;
S32 *dest = C->mixer_buffer;
for (S32 m=0; m < samples; m++)
{
dest[m] += src[m];
}
}
//
// Clip and copy contents of client's mixer buffer to output buffer
//
C8 output_buffer[TRANSMIT_QUEUE_SIZE];
S32 *src = C->mixer_buffer;
S16 *dest = (S16 *) output_buffer;
for (S32 m=0; m < samples; m++)
{
S32 s = src[m];
if (s < -32768)
{
*dest++ = -32768;
}
else if (s > 32767)
{
*dest++ = 32767;
}
else
{
*dest++ = S16(s);
}
}
//
// Add buffer to transmit queue
//
C->transmit->put_data(output_buffer,
samples * sizeof(S16));
}
Next Topic (Implementation Details)
Previous Topic (Integrating the Codecs with your Networking Architecture)
Group:
Implementing Voice Chat
For technical support, e-mail Miles3@radgametools.com
© Copyright 1991-2007 RAD Game Tools, Inc. All Rights Reserved.